home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / OpenGL / OPENGL2.EXE / _SETUP.1 / sphere.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-21  |  29.7 KB  |  934 lines

  1. #include <math.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <time.h>
  5.  
  6. #include <windows.h>
  7. #include <mmsystem.h>
  8.  
  9. #include <gl/gl.h>
  10.  
  11. #define PI_OVER_180    0.01745329F
  12. #define DEG2RAD( a )   ( (a) * PI_OVER_180 )
  13.  
  14. #define ELEMENTS_PER_VERTEX 3
  15. #define ELEMENTS_PER_NORMAL 3
  16. #define BYTES_PER_CACHELINE 32
  17.  
  18. /* struct used to manage color ramps */
  19. struct colorIndexState {
  20.     GLfloat amb[3];    /* ambient color / bottom of ramp */
  21.     GLfloat diff[3];    /* diffuse color / middle of ramp */
  22.     GLfloat spec[3];    /* specular color / top of ramp */
  23.     GLfloat ratio;    /* ratio of diffuse to specular in ramp */
  24.     GLint indexes[3];    /* where ramp was placed in palette */
  25. };
  26.  
  27. #define NUM_COLORS (sizeof(s_colors) / sizeof(s_colors[0]))
  28. struct colorIndexState s_colors[] = {
  29.     {
  30.         { 0.0F, 0.0F, 0.0F },
  31.         { 1.0F, 0.0F, 0.0F },
  32.         { 1.0F, 1.0F, 1.0F },
  33.         0.75F, { 0, 0, 0 },
  34.     },
  35.     {
  36.         { 0.0F, 0.05F, 0.05F },
  37.         { 0.9F, 0.0F, 1.0F },
  38.         { 1.0F, 1.0F, 1.0F },
  39.         1.0F, { 0, 0, 0 },
  40.     },
  41.     {
  42.         { 0.0F, 0.0F, 0.0F },
  43.         { 1.0F, 0.9F, 0.1F },
  44.         { 1.0F, 1.0F, 1.0F },
  45.         0.75F, { 0, 0, 0 },
  46.     },
  47.     {
  48.         { 0.0F, 0.0F, 0.0F },
  49.         { 0.1F, 1.0F, 0.9F },
  50.         { 1.0F, 1.0F, 1.0F },
  51.         0.75F, { 0, 0, 0 },
  52.     },
  53. };
  54.  
  55. static void (APIENTRY *LockArraysSGI)(GLint first, GLsizei count);
  56. static void (APIENTRY *UnlockArraysSGI)(void);
  57. static void (APIENTRY *CullParameterfvSGI)( GLenum pname, GLfloat *params );
  58.  
  59. static GLint s_lit_tex_indexes[3];
  60.  
  61. static int s_num_rows = 16;
  62. static int s_num_cols = 16;
  63.  
  64. static int s_winwidth  = 320;
  65. static int s_winheight = 240;
  66.  
  67. #define MS_TO_RENDER       5000
  68.  
  69. #define DRAW_VERTEX3FV          0
  70. #define DRAW_DRAW_ELEMENTS      1
  71. #define DRAW_DRAW_ARRAYS        2
  72. #define DRAW_ARRAY_ELEMENT      3
  73.  
  74. static const char *s_class_name  = "GL Sphere";
  75. static const char *s_window_name = "GL Sphere";
  76.  
  77. static BOOL    s_rgba        = TRUE;
  78. static BOOL    s_lighting    = TRUE;
  79. static BOOL    s_benchmark   = FALSE;
  80. static BOOL    s_remote      = FALSE;
  81. static BOOL    s_lock_arrays = TRUE;
  82. static BOOL    s_vcull       = TRUE;
  83.  
  84. static HPALETTE s_hPalette = NULL;
  85. static HWND     s_hWnd  = NULL;
  86. static HGLRC    s_hglrc = NULL;
  87. static HDC      s_hDC   = NULL;
  88. static int      s_bpp   = 8;
  89. static int      s_draw_method = DRAW_VERTEX3FV;
  90.  
  91. static unsigned long s_vertices_processed = 0L;
  92. static unsigned long s_triangles_processed = 0L;
  93. static float         s_elapsed_time;
  94. static unsigned long s_start, s_stop;
  95.  
  96. /*
  97. ** this maintains the data for drawing stuff via tristrips
  98. */
  99. static float **s_sphere_points;
  100. static float **s_sphere_normals;
  101.  
  102. /*
  103. ** this maintains the data for drawing stuff via vertex arrays and array elements
  104. */
  105. static float  *s_sphere_point_array;
  106. static float  *s_sphere_normal_array;
  107.  
  108. /*
  109. ** this stores the data for drawing stuff using interleaved arrays with
  110. ** draw elements
  111. */
  112. static float           *s_sphere_interleaved_array;
  113. static unsigned int   **s_sphere_elements;
  114.  
  115. /*
  116. ** this maintains the data for drawing stuff via vertex arrays and drawarrays
  117. */
  118. static float  **s_sphere_point_draw_array;
  119. static float  **s_sphere_normal_draw_array;
  120.  
  121. static BOOL    SphereCreateGeometry( int rows, int cols, float scale );
  122. static BOOL    InitSphere( HINSTANCE hInstance, LPSTR lpszCmdLine );
  123. static void    ShutdownSphere( void );
  124. static void    SphereSetDefaults( void );
  125. static void    SphereNormalizeVector( float v[3] );
  126. static void    SphereHelp( void );
  127. static void    SphereSetupPalette( HDC hDC );
  128.  
  129. static void *AllocAlignedX( int num_bytes, int byte_alignment );
  130.  
  131. static void SphereRedraw( void );
  132.  
  133. static BOOL SphereSetupPixelFormat( HDC hDC );
  134.  
  135. static LRESULT APIENTRY WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  136.  
  137.  
  138. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  139.                       LPSTR lpszCmdLine,
  140.                       int nCmdShow )
  141. {
  142.    MSG msg;
  143.  
  144.    if ( InitSphere( hInstance, lpszCmdLine ) )
  145.    {
  146.       ShowWindow( s_hWnd, nCmdShow );
  147.       UpdateWindow( s_hWnd );
  148.  
  149.       while ( 1 )
  150.       {
  151.          if ( s_benchmark )
  152.          {
  153.             int i;
  154.             int vertices_to_render = 1000000;
  155.             int frames_to_render = vertices_to_render / ( s_num_rows * ( s_num_cols * 2 + 2 ) );
  156.  
  157.             if ( frames_to_render < 1 ) frames_to_render = 1;
  158.  
  159.             s_start = timeGetTime();
  160.  
  161.             for ( i = 0; i < frames_to_render; i++ )
  162.             {
  163.                SphereRedraw();
  164.             }
  165.             glFinish();
  166.             s_stop = timeGetTime();
  167.             s_elapsed_time = ( s_stop - s_start ) / 1000.0F;
  168.             ShutdownSphere();
  169.             return 0;
  170.          }
  171.          else
  172.          {
  173.             while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) == FALSE )
  174.             {
  175.                SphereRedraw();
  176.             }
  177.             if ( GetMessage( &msg, NULL, 0, 0 ) != TRUE )
  178.             {
  179.                ShutdownSphere();
  180.                return msg.wParam;
  181.             }
  182.             TranslateMessage( &msg );
  183.             DispatchMessage( &msg );
  184.          }
  185.       }
  186.    }
  187.  
  188.    return 0;
  189. }
  190.  
  191. static LRESULT APIENTRY WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  192. {
  193.    switch ( msg )
  194.    {
  195.    case WM_CREATE:
  196.       s_hDC = GetDC( hWnd );
  197.  
  198.       if ( !SphereSetupPixelFormat( s_hDC ) )
  199.          exit( 1 );
  200.       SphereSetupPalette( s_hDC );
  201.       s_hglrc = wglCreateContext( s_hDC );
  202.       wglMakeCurrent( s_hDC, s_hglrc );
  203.       /*
  204.       ** see what kind of extensions are supported
  205.       */
  206.       if ( strstr( glGetString( GL_EXTENSIONS ), "GL_SGI_compiled_vertex_array " ) != 0 )
  207.       {
  208.           LockArraysSGI   = ( void (APIENTRY *)(GLint, GLint) ) wglGetProcAddress( "glLockArraysSGI" );
  209.           UnlockArraysSGI = ( void (APIENTRY *)( void ) )       wglGetProcAddress( "glUnlockArraysSGI" );
  210.       }
  211. #ifdef GL_SGI_cull_vertex
  212.       if ( s_vcull )
  213.       {
  214.           if ( strstr( glGetString( GL_EXTENSIONS ), "GL_SGI_cull_vertex" ) )
  215.           {
  216.               if ( ( CullParameterfvSGI = ( void (APIENTRY *)(GLenum, GLfloat*) ) wglGetProcAddress( "glCullParameterfvSGI" ) ) == 0 )
  217.               {
  218.                   MessageBox( 0, "-vcull specified but wglGetProcAddress failed", "Sphere Warning", MB_OK | MB_ICONINFORMATION );
  219.                   s_vcull = FALSE;
  220.               }
  221.           }
  222.           else
  223.           {
  224.               s_vcull = FALSE;
  225.               MessageBox( 0, "-vcull specified but no vcull extension exists", "Sphere Warning", MB_OK | MB_ICONINFORMATION );
  226.           }
  227.       }
  228. #endif
  229.  
  230.       SphereSetDefaults();
  231.  
  232.       /*
  233.       ** set vertex and normal array pointers
  234.       */
  235.       if ( s_draw_method == DRAW_ARRAY_ELEMENT )
  236.       {
  237.       glEnableClientState( GL_VERTEX_ARRAY );
  238.       glEnableClientState( GL_NORMAL_ARRAY );
  239.       glVertexPointer( ELEMENTS_PER_VERTEX, GL_FLOAT, 0, ( const GLvoid * ) s_sphere_point_array );
  240.       glNormalPointer( GL_FLOAT, ELEMENTS_PER_NORMAL * sizeof( float ) , ( const GLfloat * ) s_sphere_normal_array );
  241.       }
  242.       else if ( s_draw_method == DRAW_DRAW_ARRAYS )
  243.       {
  244.       glEnableClientState( GL_VERTEX_ARRAY );
  245.       glEnableClientState( GL_NORMAL_ARRAY );
  246.       }
  247.       else if ( s_draw_method == DRAW_DRAW_ELEMENTS )
  248.       {
  249.       }
  250.  
  251.       {
  252.          char  buffer[1000], buf2[1000];
  253.          char *dummy;
  254.          
  255.          SearchPath( NULL, "opengl32.dll", NULL, 1000, buffer, &dummy );
  256.          sprintf( buf2, "GL Sphere (%s)", buffer );
  257.          SetWindowText( hWnd, buf2 );
  258.       }
  259.       return 0;
  260.    case WM_DESTROY:
  261.       PostQuitMessage( 0 );
  262.       return 0;
  263.    case WM_CHAR:    
  264.       switch ( wParam )
  265.       {
  266.       case 'd':
  267.           s_draw_method = DRAW_DRAW_ELEMENTS;
  268.           glDisableClientState( GL_VERTEX_ARRAY );
  269.           glDisableClientState( GL_NORMAL_ARRAY );
  270.           break;
  271.       case 'a':
  272.           s_draw_method = DRAW_DRAW_ARRAYS;
  273.           glEnableClientState( GL_VERTEX_ARRAY );
  274.           glEnableClientState( GL_NORMAL_ARRAY );
  275.           break;
  276.       case 'l':
  277.           s_lock_arrays = !s_lock_arrays;
  278.           break;
  279.       case 27:
  280.          PostQuitMessage( 0 );
  281.          return 0;
  282.       }
  283.       break;
  284.    case WM_SIZE:
  285.        if ( s_hglrc )
  286.        {
  287.            int winWidth  = ( int ) LOWORD( lParam );
  288.            int winHeight = ( int ) HIWORD( lParam );
  289.  
  290.            glViewport( 0, 0, winWidth, winHeight );
  291.        }
  292.        return 0;
  293.    case WM_PALETTECHANGED:
  294.        if (s_hPalette != NULL && (HWND) wParam != hWnd) 
  295.        {
  296.            UnrealizeObject( s_hPalette );
  297.            SelectPalette( s_hDC, s_hPalette, FALSE );
  298.            RealizePalette( s_hDC );
  299.            return 0;
  300.        }
  301.        break;
  302.    case WM_QUERYNEWPALETTE:
  303.        if ( s_hPalette != NULL ) 
  304.        {
  305.            UnrealizeObject( s_hPalette );
  306.            SelectPalette( s_hDC, s_hPalette, FALSE );
  307.            RealizePalette( s_hDC );
  308.            return TRUE;
  309.        }
  310.        break;
  311.    case WM_COMMAND:
  312.       break;
  313.    }
  314.  
  315.    return DefWindowProc( hWnd, msg, wParam, lParam);
  316. }
  317.  
  318. static BOOL InitSphere( HINSTANCE hInstance, LPSTR lpszCmdLine )
  319. {
  320.    WNDCLASS wc;
  321.    
  322.    wc.style       = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
  323.    wc.lpfnWndProc = WndProc;
  324.    wc.cbClsExtra  = 0;
  325.    wc.cbWndExtra  = 0;
  326.    wc.hInstance   = hInstance;
  327.    wc.hIcon       = LoadIcon(NULL, IDI_APPLICATION);
  328.    wc.hCursor     = LoadCursor(NULL, IDC_ARROW);
  329.    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  330.    wc.lpszMenuName = NULL;
  331.    wc.lpszClassName = s_class_name;
  332.    
  333.    RegisterClass( &wc );
  334.    
  335.    {
  336.       HDC hdc = GetDC( 0 );
  337.       
  338.       s_bpp = GetDeviceCaps( hdc, BITSPIXEL );
  339.  
  340. #if NOTYET
  341.       if ( ( s_bpp <= 8 ) && !strstr( lpszCmdLine, "-332" ) )
  342.          s_rgba = 0;
  343.       else 
  344. #endif
  345.  
  346.       s_rgba = 1;
  347.       
  348.       ReleaseDC( 0, hdc );
  349.    }
  350.  
  351.    /*
  352.    ** check to see how to draw the sphere
  353.    */
  354.    if ( strstr( lpszCmdLine, "-arrayelement" ) )
  355.       s_draw_method = DRAW_ARRAY_ELEMENT;
  356.    else if ( strstr( lpszCmdLine, "-drawarrays" ) )
  357.       s_draw_method = DRAW_DRAW_ARRAYS;
  358.    else if ( strstr( lpszCmdLine, "-drawelements" ) )
  359.       s_draw_method = DRAW_DRAW_ELEMENTS;
  360.    else
  361.       s_draw_method = DRAW_VERTEX3FV;
  362.  
  363.    if ( strstr( lpszCmdLine, "-benchmark" ) )
  364.       s_benchmark = TRUE;
  365.    if ( strstr( lpszCmdLine, "-remote" ) )
  366.       s_remote = TRUE;
  367.  
  368.    if ( strstr( lpszCmdLine, "-rows:" ) )
  369.    {
  370.       s_num_rows = atoi( strchr( strstr( lpszCmdLine, "-rows:" ), ':' ) + 1 );
  371.    }
  372.    if ( strstr( lpszCmdLine, "-cols:" ) )
  373.    {
  374.       s_num_cols = atoi( strchr( strstr( lpszCmdLine, "-cols:" ), ':' ) + 1 );
  375.    }
  376.  
  377.    if ( strstr( lpszCmdLine, "-nolockarrays" ) )
  378.       s_lock_arrays = FALSE;
  379.  
  380.    if ( strstr( lpszCmdLine, "-novcull" ) )
  381.        s_vcull = FALSE;
  382.  
  383.    if ( strstr( lpszCmdLine, "-?" ) || strstr( lpszCmdLine, "/?" ) )
  384.    {
  385.       SphereHelp();
  386.       return FALSE;
  387.    }
  388.  
  389.    if ( strstr( lpszCmdLine, "-width:" ) )
  390.        s_winwidth  = atoi( strchr( strstr( lpszCmdLine, "-width:" ), ':' ) + 1 );
  391.    if ( strstr( lpszCmdLine, "-height:" ) )
  392.        s_winheight = atoi( strchr( strstr( lpszCmdLine, "-height:" ), ':' ) + 1 );
  393.  
  394.    /*
  395.    ** create geometry
  396.    */
  397.    if ( !SphereCreateGeometry( s_num_rows, s_num_cols, 1.0F ) )
  398.       return FALSE;
  399.  
  400.    /*
  401.    ** create a window of the previously defined class
  402.    */
  403.    s_hWnd = CreateWindow( s_class_name,
  404.                           s_window_name, 
  405.                           WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  406.                           10, 10, 
  407.                           s_winwidth, s_winheight,
  408.                           NULL,
  409.                           NULL,
  410.                           hInstance,
  411.                           NULL );
  412.  
  413.    if ( s_hWnd != NULL )
  414.       return TRUE;
  415.    return FALSE;
  416. }
  417.  
  418. void ShutdownSphere( void )
  419. {
  420.    if ( s_benchmark && !s_remote )
  421.    {
  422.       char buffer[1000]="";
  423.       char temp[100];
  424.  
  425.       sprintf( temp, "Vendor: %s\n\n", glGetString( GL_VENDOR ) );
  426.       strcat( buffer, temp );
  427.  
  428.       sprintf( temp, "%.2f vertices/second\n", s_vertices_processed / s_elapsed_time );
  429.       strcat( buffer, temp );
  430.  
  431.       sprintf( temp, "%.2f triangles/second\n", s_triangles_processed / s_elapsed_time );
  432.       strcat( buffer, temp );
  433.  
  434.       MessageBox( 0, buffer, "Performance", MB_OK | MB_ICONINFORMATION );
  435.    }
  436.  
  437.    if ( s_hglrc )
  438.    {
  439.       wglMakeCurrent( NULL, NULL );
  440.       wglDeleteContext( s_hglrc );
  441.    }
  442.    ReleaseDC( s_hWnd, s_hDC );
  443.  
  444. }
  445.  
  446. static BOOL SphereSetupPixelFormat( HDC hDC )
  447. {
  448.    unsigned char pixelType = s_rgba ? PFD_TYPE_RGBA : PFD_TYPE_COLORINDEX;
  449.    PIXELFORMATDESCRIPTOR pfd = 
  450.    {
  451.       sizeof( PIXELFORMATDESCRIPTOR ),
  452.       1,
  453.       PFD_DRAW_TO_WINDOW |    PFD_SUPPORT_OPENGL |    PFD_DOUBLEBUFFER,
  454.       pixelType,
  455.       s_bpp,
  456.       0, 0, 0, 0, 0, 0,
  457.       0,
  458.       0,
  459.       0,
  460.       0, 0, 0, 0,
  461.       16,                 // 16-bit depth buffer
  462.       0,                  // no stencil buffer
  463.       0,                  // no aux buffers
  464.       PFD_MAIN_PLANE,            /* main layer */
  465.       0,    
  466.       0, 0, 0
  467.    };
  468.    int  selected_pf;
  469.    
  470.    if ( ( selected_pf = ChoosePixelFormat( hDC, &pfd ) ) == 0 )
  471.    {
  472.       MessageBox( 0, "Failed to find acceptable pixel format", "GL Sphere Error", MB_ICONERROR | MB_OK );
  473.       return FALSE;
  474.    }
  475.    
  476.    if ( !SetPixelFormat( hDC, selected_pf, &pfd) )
  477.    {
  478.       MessageBox( 0, "Failed to SetPixelFormat", "GL Sphere Error", MB_ICONERROR | MB_OK );
  479.       return FALSE;
  480.    }
  481.    return TRUE;
  482. }
  483.  
  484. static void SphereSetDefaults( void )
  485. {
  486.    // setup a default color
  487.    glColor3f( 1.0F, 1.0F, 1.0F );
  488.    glClearColor( 0.0F, 0.0F, 1.0F, 1.0F );
  489.  
  490. #if 0
  491.    glClearDepth( 1.0F );
  492.    glDepthFunc( GL_LEQUAL );
  493.    glEnable( GL_DEPTH_TEST );
  494.    glDepthMask( GL_TRUE );
  495. #endif
  496.  
  497.    // setup perspective
  498.    glMatrixMode( GL_PROJECTION );
  499.    glFrustum( -0.5, 0.5, -0.5, 0.5, 1.0, 1000.0 );
  500.  
  501.    // setup viewer
  502.    glMatrixMode( GL_MODELVIEW );
  503.    glLoadIdentity();
  504.    glTranslatef( 0.0F, 0.0F, -3.0F );
  505.  
  506.    // setup Z-buffering
  507.    // setup shade model
  508.    glShadeModel( GL_SMOOTH );
  509.  
  510.    // setup lighting
  511.    if ( !s_lighting )
  512.    {
  513.       glDisable( GL_LIGHTING );
  514.       glDisable( GL_LIGHT0 );
  515.    }
  516.    else
  517.    {
  518.       GLfloat light0Pos[4] = { 0.70F, 0.70F, 1.25F, 0.00F };
  519.       GLfloat matAmb[4] = { 0.01F, 0.01F, 0.01F, 1.00F };
  520.       GLfloat matDiff[4] = { 0.65F, 0.05F, 0.20F, 0.60F };
  521.       GLfloat matSpec[4] = { 0.50F, 0.50F, 0.50F, 1.00F };
  522.       GLfloat matShine = 20.00F;
  523.  
  524.       glEnable( GL_LIGHTING );
  525.       glEnable( GL_LIGHT0 );
  526.       glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
  527.       glMaterialfv(GL_FRONT, GL_AMBIENT, matAmb);
  528.       glMaterialfv(GL_FRONT, GL_DIFFUSE, matDiff);
  529.       glMaterialfv(GL_FRONT, GL_SPECULAR, matSpec);
  530.       glMaterialf(GL_FRONT, GL_SHININESS, matShine);
  531.    }
  532.  
  533.    // setup cull mode
  534.    glEnable( GL_CULL_FACE );
  535.  
  536. #ifdef GL_SGI_cull_vertex
  537.    if ( s_vcull )
  538.    {
  539.        GLfloat eyeDir[] = { 0.0F, 0.0F, 1.0F, 0.0F };
  540.  
  541.        glEnable(GL_CULL_VERTEX_SGI);
  542.  
  543.        if ( CullParameterfvSGI )
  544.            CullParameterfvSGI( GL_CULL_VERTEX_EYE_POSITION_SGI, eyeDir );
  545.    }
  546.    else
  547.    {
  548.        glDisable(GL_CULL_VERTEX_SGI);
  549.    }
  550. #endif
  551.  
  552.    // setup dither
  553.    glEnable( GL_DITHER );
  554.  
  555.    glClear( GL_COLOR_BUFFER_BIT );
  556.    SwapBuffers( s_hDC );
  557. }
  558.  
  559. static BOOL SphereCreateGeometry( int rows, int cols, float scale )
  560. {
  561.    float   cap_offset = 10.0F;
  562.  
  563.    float   x_delta = ( 360.0F - 2.0f * cap_offset ) / cols;
  564.    float   y_delta = ( 180.0F - 2.0f * cap_offset ) / rows;
  565.    int     row, col;
  566.    int     num_vertex_rows = rows + 1;
  567.    int     num_vertex_cols = cols;
  568.  
  569.    float  *spa, *sna, *sia;
  570.  
  571.    s_sphere_points  = ( float ** ) AllocAlignedX( sizeof( float ) * num_vertex_rows, BYTES_PER_CACHELINE );
  572.    s_sphere_normals = ( float ** ) AllocAlignedX( sizeof( float ) * num_vertex_rows, BYTES_PER_CACHELINE );
  573.  
  574.    spa = s_sphere_point_array  = ( float * ) AllocAlignedX( sizeof( float ) * ELEMENTS_PER_VERTEX * num_vertex_rows * num_vertex_cols, BYTES_PER_CACHELINE );
  575.    sna = s_sphere_normal_array = ( float * ) AllocAlignedX( sizeof( float ) * ELEMENTS_PER_NORMAL * num_vertex_rows * num_vertex_cols, BYTES_PER_CACHELINE );
  576.  
  577.    if ( !s_sphere_points || !s_sphere_normals || !s_sphere_point_array || !s_sphere_normal_array )
  578.       return FALSE;
  579.  
  580.    for ( row = 0; row < num_vertex_rows; row++ )
  581.    {
  582.       s_sphere_points[row]  = ( float * ) AllocAlignedX( sizeof( float ) * num_vertex_cols * ELEMENTS_PER_VERTEX, BYTES_PER_CACHELINE );
  583.       s_sphere_normals[row] = ( float * ) AllocAlignedX( sizeof( float ) * num_vertex_cols * ELEMENTS_PER_NORMAL, BYTES_PER_CACHELINE );
  584.    }
  585.  
  586.    for ( row = 0; row < num_vertex_rows; row++ )
  587.    {
  588.       float rowangle;
  589.  
  590.       rowangle = row*y_delta + cap_offset;
  591.  
  592.       for ( col = 0; col < num_vertex_cols; col++ )
  593.       {
  594.          float colangle;
  595.  
  596.          colangle = col*x_delta;
  597.  
  598.          spa[0] = s_sphere_points[row][col*ELEMENTS_PER_VERTEX+0] = ( float ) ( sin( DEG2RAD( colangle ) ) * sin ( DEG2RAD( rowangle ) ) * scale );
  599.          spa[1] = s_sphere_points[row][col*ELEMENTS_PER_VERTEX+1] = ( float ) ( sin( DEG2RAD( rowangle + 270.0F ) ) * scale );
  600.          spa[2] = s_sphere_points[row][col*ELEMENTS_PER_VERTEX+2] = ( float ) ( sin( DEG2RAD( colangle + 270.0F ) ) * sin ( DEG2RAD( rowangle ) ) * scale );
  601. #if ( ELEMENTS_PER_VERTEX == 4 )
  602.          spa[3] = s_sphere_points[row][col*ELEMENTS_PER_VERTEX+3] = 1.0F;
  603. #endif
  604.  
  605.          spa += ELEMENTS_PER_VERTEX;
  606.  
  607.          sna[0] = s_sphere_normals[row][col*ELEMENTS_PER_NORMAL+0] = s_sphere_points[row][col*ELEMENTS_PER_VERTEX+0];
  608.          sna[1] = s_sphere_normals[row][col*ELEMENTS_PER_NORMAL+1] = s_sphere_points[row][col*ELEMENTS_PER_VERTEX+1];
  609.          sna[2] = s_sphere_normals[row][col*ELEMENTS_PER_NORMAL+2] = s_sphere_points[row][col*ELEMENTS_PER_VERTEX+2];
  610. #if ( ELEMENTS_PER_NORMAL == 4 )
  611.          sna[3] = s_sphere_normals[row][col*ELEMENTS_PER_NORMAL+3] = 1.0F;
  612. #endif
  613.  
  614.          SphereNormalizeVector( &s_sphere_normals[row][col*ELEMENTS_PER_NORMAL] );
  615.          SphereNormalizeVector( sna );
  616.  
  617.          sna += ELEMENTS_PER_NORMAL;
  618.       }
  619.    }
  620.  
  621.    /*
  622.    ** create the draw arrays data
  623.    */
  624.    s_sphere_point_draw_array  = ( float ** ) AllocAlignedX( sizeof( float * ) * s_num_rows, BYTES_PER_CACHELINE );
  625.    s_sphere_normal_draw_array = ( float ** ) AllocAlignedX( sizeof( float * ) * s_num_rows, BYTES_PER_CACHELINE );
  626.  
  627.    for ( row = 0; row < s_num_rows; row++ )
  628.    {
  629.       s_sphere_point_draw_array[row]  = ( float * ) AllocAlignedX( sizeof( float ) * ELEMENTS_PER_VERTEX * ( s_num_cols + 1 ) * 2, BYTES_PER_CACHELINE );
  630.       s_sphere_normal_draw_array[row] = ( float * ) AllocAlignedX( sizeof( float ) * ELEMENTS_PER_NORMAL * ( s_num_cols + 1 ) * 2, BYTES_PER_CACHELINE );
  631.    }
  632.    for ( row = 0; row < s_num_rows; row++ )
  633.    {
  634.       for ( col = 0; col < s_num_cols; col++ )
  635.       {
  636.          float *pdst, *psrc;
  637.  
  638.          pdst = &s_sphere_point_draw_array[row][col*2*ELEMENTS_PER_VERTEX];
  639.          psrc = &s_sphere_points[row][col*ELEMENTS_PER_VERTEX];
  640.          memcpy( pdst, psrc, sizeof( float ) * ELEMENTS_PER_VERTEX );
  641.  
  642.          pdst = &s_sphere_point_draw_array[row][(col*2+1)*ELEMENTS_PER_VERTEX];
  643.          psrc = &s_sphere_points[row+1][col*ELEMENTS_PER_VERTEX];
  644.          memcpy( pdst, psrc, sizeof( float ) * ELEMENTS_PER_VERTEX );
  645.  
  646.          pdst = &s_sphere_normal_draw_array[row][col*2*ELEMENTS_PER_NORMAL];
  647.          psrc = &s_sphere_normals[row][col*ELEMENTS_PER_NORMAL];
  648.          memcpy( pdst, psrc, sizeof( float ) * ELEMENTS_PER_NORMAL );
  649.  
  650.          pdst = &s_sphere_normal_draw_array[row][(col*2+1)*ELEMENTS_PER_NORMAL];
  651.          psrc = &s_sphere_normals[row+1][col*ELEMENTS_PER_NORMAL];
  652.          memcpy( pdst, psrc, sizeof( float ) * ELEMENTS_PER_NORMAL );
  653.       }
  654.       memcpy( &s_sphere_point_draw_array[row][s_num_cols*2*ELEMENTS_PER_VERTEX],      &s_sphere_points[row][0],    sizeof( float ) * ELEMENTS_PER_VERTEX );
  655.       memcpy( &s_sphere_point_draw_array[row][(s_num_cols*2+1)*ELEMENTS_PER_VERTEX],  &s_sphere_points[row+1][0],  sizeof( float ) * ELEMENTS_PER_VERTEX );
  656.       memcpy( &s_sphere_normal_draw_array[row][s_num_cols*2*ELEMENTS_PER_NORMAL],     &s_sphere_normals[row][0],   sizeof( float ) * ELEMENTS_PER_NORMAL );
  657.       memcpy( &s_sphere_normal_draw_array[row][(s_num_cols*2+1)*ELEMENTS_PER_NORMAL], &s_sphere_normals[row+1][0], sizeof( float ) * ELEMENTS_PER_NORMAL );
  658.    }
  659.  
  660.    /*
  661.    ** create the draw elements data
  662.    */
  663.    s_sphere_elements = ( unsigned int ** ) malloc( sizeof( unsigned int * ) * s_num_rows );
  664.    for ( row = 0; row < s_num_rows; row++ )
  665.    {
  666.       s_sphere_elements[row] = ( unsigned int * ) malloc( sizeof( unsigned int ) * ( 2 * s_num_cols + 2 ) );
  667.    }
  668.    for ( row = 0; row < s_num_rows; row++ )
  669.    {
  670.       for ( col = 0; col < s_num_cols*2; col += 2 )
  671.       {
  672.          s_sphere_elements[row][col]   = row * s_num_cols + col/2;
  673.          s_sphere_elements[row][col+1] = ( row + 1 ) * s_num_cols + col/2;
  674.       }
  675.  
  676.       s_sphere_elements[row][s_num_cols*2]   = row * s_num_cols;
  677.       s_sphere_elements[row][s_num_cols*2+1] = ( row + 1 ) * s_num_cols;
  678.    }
  679.    sia = s_sphere_interleaved_array = ( float * ) malloc( sizeof( float ) * ELEMENTS_PER_VERTEX * ELEMENTS_PER_NORMAL * ( s_num_rows + 1 ) * ( s_num_cols + 1 ) );
  680.    memset( s_sphere_interleaved_array, 0, sizeof( float ) * ELEMENTS_PER_VERTEX * ELEMENTS_PER_NORMAL * ( s_num_rows + 1 ) * ( s_num_cols + 1 ) );
  681.  
  682.    for ( row = 0; row < num_vertex_rows; row++ )
  683.    {
  684.       for ( col = 0; col < s_num_cols; col++ )
  685.       {
  686.          memcpy( sia, &s_sphere_normals[row][col*ELEMENTS_PER_NORMAL], sizeof( float ) * ELEMENTS_PER_NORMAL );
  687.  
  688.          sia += ELEMENTS_PER_NORMAL;
  689.  
  690.          memcpy( sia, &s_sphere_points[row][col*ELEMENTS_PER_VERTEX], sizeof( float ) * ELEMENTS_PER_VERTEX );
  691.  
  692.          sia += ELEMENTS_PER_VERTEX;
  693.       }
  694.    }
  695.  
  696.    return TRUE;
  697. }
  698.  
  699. static void SphereRedraw( void )
  700. {
  701.    int row, col;
  702.  
  703.    if ( !s_benchmark )
  704.       glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  705.  
  706.    glRotatef( 1.0f, 0.0F, 1.0F, 0.0F );
  707.    glRotatef( 1.0f, 1.0F, 0.0F, 0.0F );
  708.  
  709.    if ( s_draw_method == DRAW_VERTEX3FV )
  710.    {
  711.       for ( row = 0; row < s_num_rows; row++ )
  712.       {
  713.          glBegin( GL_TRIANGLE_STRIP );
  714.          for ( col = 0; col < s_num_cols; col++ )
  715.          {
  716.             glNormal3fv( &s_sphere_normals[row][col*ELEMENTS_PER_NORMAL] );
  717.             glVertex3fv( &s_sphere_points[row][col*ELEMENTS_PER_VERTEX] );
  718.             glNormal3fv( &s_sphere_normals[row+1][col*ELEMENTS_PER_NORMAL] );
  719.             glVertex3fv( &s_sphere_points[row+1][col*ELEMENTS_PER_VERTEX] );
  720.          }
  721.          glNormal3fv( &s_sphere_normals[row][0] );
  722.          glVertex3fv( &s_sphere_points[row][0] );
  723.          glNormal3fv( &s_sphere_normals[row+1][0] );
  724.          glVertex3fv( &s_sphere_points[row+1][0] );
  725.          
  726.          glEnd();
  727.       }
  728.    }
  729.    else if ( s_draw_method == DRAW_DRAW_ARRAYS )
  730.    {
  731.       for ( row = 0; row < s_num_rows; row++ )
  732.       {
  733.          glVertexPointer( ELEMENTS_PER_VERTEX, GL_FLOAT, ELEMENTS_PER_VERTEX * sizeof( float ), ( const GLvoid * )  s_sphere_point_draw_array[row] );
  734.          glNormalPointer( GL_FLOAT, ELEMENTS_PER_NORMAL * sizeof( float ), ( const GLfloat * ) s_sphere_normal_draw_array[row] );
  735.          glDrawArrays( GL_TRIANGLE_STRIP, 0, (s_num_cols+1)*2 );
  736.       }
  737.    }
  738.    else if ( s_draw_method == DRAW_ARRAY_ELEMENT )
  739.    {
  740.       for ( row = 0; row < s_num_rows; row++ )
  741.       {
  742.          glBegin( GL_TRIANGLE_STRIP );
  743.  
  744.          for ( col = 0; col < s_num_cols; col++ )
  745.          {
  746.             glArrayElement( col + row*s_num_cols );
  747.             glArrayElement( col + (row+1)*s_num_cols );
  748.          }
  749.  
  750.          glArrayElement( row*s_num_cols );
  751.          glArrayElement( (row+1)*s_num_cols );
  752.  
  753.          glEnd();
  754.       }
  755.    }
  756.    else if ( s_draw_method == DRAW_DRAW_ELEMENTS )
  757.    {
  758.       glInterleavedArrays( GL_N3F_V3F, ( ELEMENTS_PER_VERTEX + ELEMENTS_PER_NORMAL ) * sizeof( float ), s_sphere_interleaved_array );
  759.  
  760.       if ( LockArraysSGI && s_lock_arrays )
  761.       {
  762.          LockArraysSGI( 0, ( s_num_rows + 1 ) * ( s_num_cols + 1 ) );
  763.       }
  764.  
  765.       for ( row = 0; row < s_num_rows; row++ )
  766.       {
  767.          glDrawElements( GL_TRIANGLE_STRIP, (s_num_cols+1)*2, GL_UNSIGNED_INT, s_sphere_elements[row] );
  768.       }
  769.  
  770.       if ( UnlockArraysSGI && s_lock_arrays )
  771.       {
  772.          UnlockArraysSGI();
  773.       }
  774.    }
  775.  
  776.    s_vertices_processed  += ( ( s_num_rows + 1 ) * ( s_num_cols ) );
  777.    s_triangles_processed += ( s_num_rows * s_num_cols );
  778.  
  779.    if ( !s_benchmark )
  780.      SwapBuffers( s_hDC );
  781. }
  782.  
  783. static void SphereNormalizeVector( float v[3] )
  784. {
  785.    float m = 1.0F / ( float ) ( sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ) );
  786.  
  787.    v[0] *= m;
  788.    v[1] *= m;
  789.    v[2] *= m;
  790. }
  791.  
  792. static void *AllocAlignedX( int num_bytes, int byte_alignment )
  793. {
  794.    void *buf = malloc( num_bytes + byte_alignment );
  795.    unsigned long q = ( unsigned long ) buf;
  796.  
  797.    q += byte_alignment;
  798.  
  799.    q &= ~( byte_alignment - 1 );
  800.  
  801.    return ( void * ) q;
  802. }
  803.  
  804. static void SphereHelp( void )
  805. {
  806.    char superbuffer[1000]=
  807.       "-?\t\tthis help screen\n"
  808.       "-arrayelements\tuse glArrayElement\n"
  809.       "-drawelements\tuse glDrawElements\n"
  810.       "-drawarrays\tuse glDrawArrays\n"
  811.       "-tristrip\t\tuse triangle strips w/ glVertex3fv\n"
  812.       "-vcull\t\tuse SGI's vertex culling extension\n"
  813.       "-lockarrays\tuse SGI's lock arrays extension when doing drawelements\n\n"
  814.       "-cols:val\t\tspecify number of vertical (longitudinal) bands in sphere\n"
  815.       "-rows:val\t\tspecify number of horizontal (latitudinal) bands in sphere\n\n"
  816.       "-width:val\t\twidth of window, in pixels (default is 320)\n"
  817.       "-height:val\t\theight of window, in pixels (default is 240)\n\n"
  818.       "-benchmark\trun as benchmark and immediately quit when done\n"
  819.       "-remote\t\tdon't print performance data\n";
  820.  
  821.    MessageBox( 0, superbuffer, "Sphere, Copyright (C) 1997 Silicon Graphics, Inc.", MB_OK | MB_ICONINFORMATION );
  822. }
  823.  
  824. static void SphereSetupPalette( HDC hDC )
  825. {
  826.     PIXELFORMATDESCRIPTOR  pfd;
  827.     LOGPALETTE            *pPal;
  828.     int                    paletteSize;
  829.     int                    pixelFormat = GetPixelFormat(hDC);
  830.     
  831.     DescribePixelFormat( hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
  832.  
  833.     if (!(pfd.dwFlags & PFD_NEED_PALETTE || pfd.iPixelType == PFD_TYPE_COLORINDEX))
  834.         return;
  835.     
  836.     paletteSize = 1 << pfd.cColorBits;
  837.  
  838.     pPal                = (LOGPALETTE * ) malloc( sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY) );
  839.     pPal->palVersion    = 0x300;
  840.     pPal->palNumEntries = paletteSize;
  841.     
  842.     /* start with a copy of the current system palette */
  843.     GetSystemPaletteEntries( hDC, 0, paletteSize, &pPal->palPalEntry[0] );
  844.     
  845.     if ( pfd.iPixelType == PFD_TYPE_RGBA )
  846.     {
  847.         /* fill in an RGBA color palette */
  848.         int redMask = (1 << pfd.cRedBits) - 1;
  849.         int greenMask = (1 << pfd.cGreenBits) - 1;
  850.         int blueMask = (1 << pfd.cBlueBits) - 1;
  851.         int i;
  852.         
  853.         for (i=0; i<paletteSize; ++i) 
  854.         {
  855.             pPal->palPalEntry[i].peRed =
  856.                 (((i >> pfd.cRedShift) & redMask) * 255) / redMask;
  857.             pPal->palPalEntry[i].peGreen =
  858.                 (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
  859.             pPal->palPalEntry[i].peBlue =
  860.                 (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
  861.             pPal->palPalEntry[i].peFlags = 0;
  862.         }
  863.     } 
  864.     else 
  865.     {
  866.         /* fill in a Color Index ramp color palette */
  867.         int numRamps = NUM_COLORS;
  868.         int rampSize = (paletteSize - 20) / numRamps;
  869.         int extra = (paletteSize - 20) - (numRamps * rampSize);
  870.         int i, r;
  871.         
  872.         for (r=0; r<numRamps; ++r) 
  873.         {
  874.             int rampBase = r * rampSize + 10;
  875.             PALETTEENTRY *pe = &pPal->palPalEntry[rampBase];
  876.             int diffSize = (int) (rampSize * s_colors[r].ratio);
  877.             int specSize = rampSize - diffSize;
  878.             
  879.             for (i=0; i<rampSize; ++i) 
  880.             {
  881.                 GLfloat *c0, *c1;
  882.                 GLint a;
  883.                 
  884.                 if (i < diffSize) 
  885.                 {
  886.                     c0 = s_colors[r].amb;
  887.                     c1 = s_colors[r].diff;
  888.                     a = (i * 255) / (diffSize - 1);
  889.                 } 
  890.                 else 
  891.                 {
  892.                     c0 = s_colors[r].diff;
  893.                     c1 = s_colors[r].spec;
  894.                     a = ((i - diffSize) * 255) / (specSize - 1);
  895.                 }
  896.                 
  897.                 pe[i].peRed = (BYTE) (a * (c1[0] - c0[0]) + 255 * c0[0]);
  898.                 pe[i].peGreen = (BYTE) (a * (c1[1] - c0[1]) + 255 * c0[1]);
  899.                 pe[i].peBlue = (BYTE) (a * (c1[2] - c0[2]) + 255 * c0[2]);
  900.                 pe[i].peFlags = PC_NOCOLLAPSE;
  901.             }
  902.             
  903.             s_colors[r].indexes[0] = rampBase;
  904.             s_colors[r].indexes[1] = rampBase + (diffSize-1);
  905.             s_colors[r].indexes[2] = rampBase + (rampSize-1);
  906.         }
  907.         s_lit_tex_indexes[0] = 0;
  908.         s_lit_tex_indexes[1] = (GLint)(rampSize*s_colors[0].ratio)-1;
  909.         s_lit_tex_indexes[2] = rampSize-1;
  910.         
  911.         for (i=0; i<extra; ++i) 
  912.         {
  913.             int index = numRamps*rampSize+10+i;
  914.             PALETTEENTRY *pe = &pPal->palPalEntry[index];
  915.             
  916.             pe->peRed = (BYTE) 0;
  917.             pe->peGreen = (BYTE) 0;
  918.             pe->peBlue = (BYTE) 0;
  919.             pe->peFlags = PC_NOCOLLAPSE;
  920.         }
  921.     }
  922.     
  923.     s_hPalette = CreatePalette( pPal );
  924.     free( pPal );
  925.     
  926.     if ( s_hPalette )
  927.     {
  928.         SelectPalette( hDC, s_hPalette, FALSE );
  929.         RealizePalette( hDC );
  930.     }
  931. }
  932.  
  933. 
  934.